
<script setup>
	
	import tools from '@/utils';
	import spellApi from '@/common/apis/spell';
	import wordWifi from './components/wifi.vue';
	import { ref, reactive, computed, nextTick, getCurrentInstance, onBeforeUnmount } from 'vue';
	
	
	/** 单词列表 */
	const wordlist = reactive(uni.getStorageSync('_vocabulary-list'));
	// uni.removeStorageSync('_vocabulary-list');
	
	
	/** 当前词汇索引 */
	const wordIndex = ref(0);
	
	/** 可视屏幕 */
	const screen = (() => {
		const query = { width: 0, height: 0 };
		
		// #ifdef MP-WEIXIN
		query.width = wx.getWindowInfo().screenWidth;
		query.height = wx.getWindowInfo().screenHeight;
		// #endif
		
		// #ifndef MP-WEIXIN
		query.width = wx.getSystemInfoSync().screenWidth;
		query.height = wx.getSystemInfoSync().screenHeight;
		// #endif
		
		return query;
	})();
	
	
	/** 拼写状态 */
	const spellingState = ref(true);
	
	/** 拼写结果 */
	const spellingResult = ref('');
	
	/** 当前拼写数据 */
	const currentSpellingData = computed(() => wordlist[wordIndex.value]);
	
	
	/** 当前单词详细 */
	const wordInfo = ref({});
	
	/** 拼写单词 */
	const spellWord = ref('');
	
	/** 拼接单词 */
	const joinWord = () => {
		const _spellingResult = wordInfo.value.syllableChars.reduce((str, key) => {
			const _str = `${key === wordInfo.value.rightAnswer.content ? '_' : key}`;
			str += _str;
			return str;
			
		}, '');
		
		spellingResult.value = wordInfo.value.isCombine ? wordInfo.value.stem.reduce((str, key) => str += key + '·', '').slice(0, -1) : _spellingResult;
		spellWord.value = wordInfo.value.isCombine ? wordInfo.value.syllableChars.reduce((str, key) => str += key + '·', '').slice(0, -1) : currentSpellingData.value.word;
	};
	
	/** 获取当前单词详细方法 */
	const getWordInfo = async () => {
		const result = await spellApi.splitWord({
			word: currentSpellingData.value.word
		});
		
		wordInfo.value = result;
		joinWord();
	};
	
	/** 获取当前单词详细 */
	getWordInfo();
	
	
	/** 提示 */
	const hint = ref(false);
	
	
	/** 拼写常量 */
	const SPELL_COLOR = {
		/** 不在原单词范围内 */
		NO: '#8e888b',
		
		/** 错误 */
		ERROR: '#e16857',
		
		/** 正确 */
		CORRECT: '#00c386'
	};
	
	/** 选择填空 */
	const onSelect = item => {
		if (wordlist[wordIndex.value].content) return;
		spellingState.value = spellingResult.value.replace('_', item.content) === spellWord.value;
		wordlist[wordIndex.value].content = item.content;
		const findIndex = spellingResult.value.indexOf('_');
		if (!!~findIndex) {
			spellingResult.value = spellingResult.value.replace('_', `<span style="color: ${SPELL_COLOR[item.content === wordInfo.value.rightAnswer.content ? 'CORRECT' : 'ERROR']}">${item.content}</span>`);
		};
		
		if (spellingState.value) {
			hint.value = false;
			WhetherTheDefaultSpellingMode.value = spellingState.value;
			setTimeout(() => {
				inputFocus.value = true;
				
			}, 500);
		};
	};
	
	
	/** 重置填空拼写 */
	const onReset = () => {
		spellingState.value = true;
		const color = SPELL_COLOR[wordlist[wordIndex.value].content === wordInfo.value.rightAnswer.content ? 'CORRECT' : 'ERROR'];
		spellingResult.value = spellingResult.value.replace(`<span style="color: ${color}">${wordlist[wordIndex.value].content}</span>`, '_');
		wordlist[wordIndex.value].content = '';
	};
	
	
	
	/** 当前组件实例 */
	const { proxy } = getCurrentInstance();
	
	/** uv-navbar height */
	const uvNavbarHeight = ref(0);
	setTimeout(() => {
		nextTick(async () => {
			const { height } = await tools.getRect('.uv-navbar-view', proxy);
			uvNavbarHeight.value = height;
		});
	}, 20);
	

	/** input focus */
	const inputFocus = ref(false);
	
	/** 失去焦点时 */
	const onBlur = () => {
		if (!WhetherTheDefaultSpellingMode.value) return;
		inputFocus.value = true;
	};
	
	/** 输入时 */
	const onInput = () => {
		if (spellResult.value) {
			hint.value = false;
			spellResult.value = '';
			spellValue.value = record.value.filter(item => item.str !== '_').map(item => item.str).join('');
		};
	};
	
	/** 拼写值 */
	const spellValue = ref('');
	
	/** 拼写数据 */
	const spellData = uni.getStorageSync('_spell-data');
	
	/** 提交函数 */
	const _submit = async () => {
		inputFocus.value = false;
		WhetherTheDefaultSpellingMode.value = false;
		await spellApi.saveWords({ words: [{ id: currentSpellingData.value.id, isSpell: 1 }], logId: spellData.logId });
		if (wordIndex.value === wordlist.length - 1) {
			await spellApi.endSpell({ logId: spellData.logId, spellTime: 0 });
			uni.navigateBack({ 
				success: () => uni.$fui.toast('已完成本次练习') 
			});
			
		} else {
			wordIndex.value++;
		};
		
		spellValue.value = '';
		record.value = [];
		spellResult.value = '';
		hint.value = false;
		await getWordInfo();
	};
	
	
	/** 拼写结果 */
	const spellResult = ref();
	
	/** shake */
	const shake = ref(false);
	
	/** 记录 */
	const record = ref([]);
	
	/** create span */
	const createSpan = (str, color, cprrect = color === '#00c386') => {
		return {
			str,
			color,
			cprrect,
			value: function() {
				return `<span style="color: ${this.color};${str === '_' ? 'padding-right: 2px' : ''}">${this.str}</span>`;
			}
		}
	};
	
	/** 拼写转标签 */
	const spellTransferTag = () => {
		/** 拼写的每一项 */
		record.value = [];
		
		/**  原单词*/
		const word = currentSpellingData.value.word;
		
		/** 循环拼写 */
		for (let index = 0, wordIndex = 0, errorIndex = 0; index < spellValue.value.length; index++) {
			/** 拼写的每一项 */
			const spellItem = spellValue.value[index];
			
			if (word === spellValue.value) {
				/** 拼写全等 */
				record.value.push(createSpan(spellItem, SPELL_COLOR.CORRECT));
			
			} else {
				/** 拼写不全等 */
				if (spellItem === word[wordIndex]) {
					/** 正确 */
					record.value.push(createSpan(spellItem, SPELL_COLOR.CORRECT));
					wordIndex++;
					errorIndex++;
					
				} else if (record.value.length >= word.length) {
					/** 超出原单词长度 */
					record.value.push(createSpan(spellItem, SPELL_COLOR.NO));
					
				} else {
					/** 错误 */
					const returnSliceStartIndex = () => {
						let _index = word.indexOf(spellItem) + 1;
						let _word = word;
						const frequency = record.value.filter(item => item.str === spellItem).length;
						const _returnSliceStartIndex = () => {
							if (frequency <= 1) return;
							for (let _i = 0; _i <= frequency; _i++) {
								_word = _word.slice(_index);
								_index += _word.indexOf(spellItem) + 1;
							};
						};
						
						_returnSliceStartIndex();
						return frequency ? _index : errorIndex;
					};
					
					const lastWord = word.slice(returnSliceStartIndex());
					if (lastWord.includes(spellItem) && record.value.length + 1 < word.length) {
						/** 用下划线补齐单词中间的部分 */
						const underline = Array.from({ length: lastWord.indexOf(spellItem) }).map(() => createSpan('_', SPELL_COLOR.ERROR));
						underline.length && record.value.push(...underline);
						errorIndex++;
					};
					
					record.value.push(createSpan(spellItem, SPELL_COLOR[lastWord.includes(spellItem) ? 'CORRECT' : 'ERROR']));
				};
			};
		};
		
		
		if (spellValue.value.length < word.length) {
			/** 拼写的长度小于原单词的长度时 */
			record.value[record.value.find(item => item.cprrect) ? 'push' : 'unshift'](...Array.from({ length: word.length - record.value.length }).map(() => createSpan('_', SPELL_COLOR.ERROR)));
		};
		
		/** 加入到 template */
		const correctCount = record.value.filter(item => item.cprrect).length;
		spellResult.value = record.value.map((item, index) => {
			item.color = correctCount === word.length && item.color === '#e16857' ? SPELL_COLOR.NO : item.color;
			return item.value();
			
		}).join('');
	};
	
	/** 提交 */
	const onSubmit = async () => {
		hint.value = true;
		if (!spellValue.value) return;
		spellTransferTag();
		
		if (spellValue.value !== currentSpellingData.value.word) {
			spellingState.value = false;
			setTimeout(() => spellingState.value = true, 800)
			return;
		};
		
		_submit();
	};
	
	/** cursor-color */
	const cursorColor = (() => {
		// #ifndef MP-WEIXIN
		return '#46c69e';
		// #endif
		
		// #ifdef MP-WEIXIN
		return uni.getDeviceInfo().platform === 'ios' ? '#46c69e' : 'green';
		// #endif
		
	})();
	
	/** 键盘信息 */
	const keyboardheightHeight = ref(0);
	
	/** 键盘弹起事件 */
	const onKeyboardheightchange = result => {
		const height = result?.height || result?.detail?.height;
		keyboardheightHeight.value = height;
	};
	
	/** 监听键盘高度变化 */
	uni.onKeyboardHeightChange(onKeyboardheightchange);
	
	/** 组件卸载时 */
	onBeforeUnmount(() => {
		/** 移除监听键盘高度变化 */
		uni.offKeyboardHeightChange(onKeyboardheightchange);
	});
	
	
	/** 是否播放单词 */
	const isPlayWord = ref(false);
	
	/** 播放结束 */
	const playEnd = () => {
		isPlayWord.value = false;
	};
	
	/** 监听自然结束 */
	uni.useAudio.onEnded(playEnd);
	
	/** 监听播放暂停 */
	uni.useAudio.onStop(playEnd);
	
	/** 播放单词 */
	const onPlayWord = () => {
		isPlayWord.value = true;
		uni.useAudio.src(currentSpellingData.value?.voiceFile?.url);
	};
	
	
	/** 是否默认拼写模式 */
	const WhetherTheDefaultSpellingMode = ref(false);
	
	
	/** 导航栏 margin-right */
	const navRight = ref(0);
	
	// #ifdef MP-WEIXIN
	/** 获取小程序胶囊信息 */
	const { width } = uni.getMenuButtonBoundingClientRect()
	navRight.value = `${width}px`;
	// #endif
		
	
</script>

<template>
	<view class="containerbox">
		<view class="uv-navbar-view">
			<uv-navbar placeholder bg-color="transparent" auto-back left-text="拼写训练" >
				<template #right>
					<view :style="{ marginRight: navRight }">
						<text class="text-primary2">{{ wordIndex + 1 }}</text>/{{ wordlist.length }}
					</view>
				</template>
			</uv-navbar>
		</view>
		
		<progress :percent="(wordIndex + 1) / wordlist.length * 100" background-color="rgba(255,255,255,0.3)" active-color="rgba(0,195,134,0.5)" border-radius="4" stroke-width="2" active active-mode="forwards" />
		
		<view class="containerbox">
			<view class="flex flex-1 swiper" :style="{ transform: `translateX(-${wordIndex * screen.width}px)` }">
				<view
					:key="item.id"
					v-for="item in wordlist"
					class="swiper-item containerbox"
				>
					<view :style="{ width: `${screen.width}px` }" class="containerbox">
						<view class="text-center mt-300 bold h-108 text-80" :class="{ shake: !spellingState }">
							<rich-text :nodes="spellingResult" />
						</view>
						
						<view class="text-center text-26 mt-30 text-gary px-50">
							{{ item.translation }}
						</view>
						
						<view class="text-center text-40 mt-10 text-gary bold transition-opacity px-50" :style="{ opacity: Number(hint) }">
							{{ item.word }}
						</view>
						
						
						<view class="mt-auto px-50 flex items-center flex-wrap justify-between text-40 mb-30">
							<view 
								:key="index"
								@tap="onSelect(word)"
								v-for="word, index in wordInfo?.options"
								class="flex items-center justify-center word-content mb-25"
								style="width:200rpx;height:120rpx;box-shadow:0 0 5rpx #eee;border-radius:12rpx;transition:all .3s"
								:style="{ backgroundColor: item.content === word.content ? 'rgba(26,188,156,.1)' : 'rgba(255,255,255,.5)' }"
							>
								{{ word.content }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		
		
		<view class="flex items-center justify-between px-50 mt-auto pb-80 text-48">
			<view 
				@tap="hint = !hint"
				hover-class="botton-active"
				:style="hint ? 'color:#1abc9c' : ''"
				class="spell spell-tishi w-90 h-90 bgc-white round-30 flex items-center justify-center transition-color" 
			/>
			
			<view class="w-90 h-90 bgc-white round-30 flex items-center justify-center transition-bg" hover-class="botton-active" @tap="onReset">
				<uv-icon name="reload" size="46rpx" color="#000" />
			</view>
		</view>
		
		
		
		<view 
			class="fixed bgc-white w-full top-0 containerbox" 
			:class="{ 'complete-spelling-view': !!wordInfo.word && WhetherTheDefaultSpellingMode }"
			:style="{ height: `${screen.height - uvNavbarHeight}px`, top: `${WhetherTheDefaultSpellingMode ? uvNavbarHeight : screen.height}px` }"
		>
			<view class="text-center w-full mt-300 bold text-80" :class="{ shake: !spellingState }">
				<input
					type="text" 
					confirm-hold
					hold-keyboard
					@blur="onBlur"
					inputmode="none"
					@input="onInput"
					input-mode="text"
					@confirm="onSubmit"
					:focus="inputFocus" 
					v-model="spellValue"
					:cursor-color="cursorColor" 
					class="inout-view overflow-hidden text-80"
					@keyboardheightchange="onKeyboardheightchange" 
					:style="{ height: spellResult ? '0' : '108rpx', minHeight: '0' }"
				/>
				
				<view class="rich-text-view h-108" v-if="spellResult" @tap="onInput">
					<rich-text :nodes="spellResult" />
					<view class="rich-text-view-cursor-blinks" />
				</view>
			</view>
			
			<view class="text-center mt-50 px-50">
				<view class="text-center text-26 mt-30 text-gary px-50">
					{{ currentSpellingData.translation }}
				</view>
				
				<view class="text-center text-40 mt-10 bold text-gary transition-opacity px-50" :style="{ opacity: Number(hint) }">
					{{ currentSpellingData.word }}
				</view>
			</view>
			
			<view class="flex items-center justify-between px-50 mt-auto pb-30 text-48">
				<view 
					@tap="hint = !hint" 
					hover-class="botton-active"
					:style="hint ? 'color:#1abc9c' : ''"
					class="spell spell-tishi w-90 h-90 bgc-white round-30 flex items-center justify-center transition-color shadow"
				/>
				
				<view @tap="onPlayWord" class="relative w-90 h-90 bgc-white round-30 flex items-center justify-center text-30 transition-bg shadow" hover-class="botton-active" v-if="!isPlayWord">
					<view class="absolute" style="left: 40rpx; top: 20rpx; transform: scale(1.2)">
						<word-wifi color="#1abc9c" />
					</view>
				</view>
				
				<text class="px-30 h-90 bgc-white round-30 flex items-center justify-center text-30 normal text-9ca2a0 shadow" v-else>{{ currentSpellingData.soundmark }}</text>
				<view class="spell spell-zhengque w-90 h-90 bgc-white round-30 flex items-center justify-center transition-bg shadow" hover-class="botton-active" @tap="onSubmit" />
			</view>
			
			<view :style="{ height: `${keyboardheightHeight}px` }" class="transition-height" />
		</view>
	</view>
</template>


<style scoped lang="scss">
	.shadow{box-shadow: 0 0 5px rgba(0,0,0,0.2)}
	.complete-spelling-view{transition: top .5s, opacity .3s}
	.swiper{transition: transform .3s;flex-basis: fill}
	.shake{animation: shake 800ms ease-in-out;transform-style: preserve-3d}
	 @keyframes shake{
		10%,90%{transform: translate3d(-1px, 0, 0)}
		20%,80%{transform: translate3d(+2px, 0, 0)}
		30%,70%{transform: translate3d(-4px, 0, 0)}
		40%,60%{transform: translate3d(+4px, 0, 0)}
		50%{transform: translate3d(-4px, 0, 0)}
	}
</style>